using System;

using EMan.BL.EntityEditing;
using EMan.BL.Properties;
using EMan.Interface.EnterpriseStructure.Jobs;
using EMan.Interface.EntityEditing;

using TrueCode.Core.Aspects;
using TrueCode.Core.Diagnostics;
using TrueCode.Core.Exceptions;
using TrueCode.Core.Validation;

namespace EMan.BL.EnterpriseStructure.Jobs
{
  [UsedImplicitly]
  public class JobEditorPresenter : NewEnitytEditorPresenter<JobEditable>, IJobEditorPresenter
  {
    #region Fields
    private readonly JobEditable _job;
    private readonly Predicate< string > _checkNameUniqueness;
    private readonly IValidator _validator;

    private readonly EntityProperty _titleProperty;
    private readonly EntityProperty _descriptionProperty;

    private Property _validProperties = Property.All;
    #endregion

    #region .ctors
    public JobEditorPresenter( [NotNull] JobEditable jobEditable, [NotNull] IValidator validator, [NotNull] IDiagnostic diagnostic ) : base( jobEditable, diagnostic )
    {
      if( jobEditable == null ) throw new ArgumentNullException( "jobEditable" );
      if( validator == null ) throw new ArgumentNullException( "validator" );
      if( jobEditable.TitleUniquenessPredicate == null ) throw new ArgumentException( "job" );

      _job = jobEditable;
      _checkNameUniqueness = jobEditable.TitleUniquenessPredicate;
      _validator = validator;

      _titleProperty = new EntityProperty< string >( Resources.CreateJob_Name_Descripition,
                                                    () => _job.Title, SetName );

      _descriptionProperty = new EntityProperty< string >( Resources.CreateJob_Description_Description,
                                                           () => _job.Description, SetDescription );

      OkCommand.CanExecute = true;
    }
    #endregion
    
    #region .dtor
    public override void Dispose(){}
    #endregion

    #region Implementation of IJobEditorPresenter
     public IEntityProperty Title
    {
      get { return _titleProperty; }
    }

    public IEntityProperty Description
    {
      get { return _descriptionProperty; }
    }
    #endregion

    #region Private
    private void SetPropertyValid( Property property )
    {
      _validProperties |= property;
      OkCommand.CanExecute = _validProperties == Property.All;
    }

    private void SetPropertyInvalid( Property property )
    {
      _validProperties &= ~property;
      OkCommand.CanExecute = false;
    }

    private void SetName( string name )
    {
      _job.Title = name;

      

      string errorText = null;
      try
      {
        _validator.Validate( _job, () => _job.Title );
      }
      catch( ArgumentNullException )
      {
        errorText = string.Format( Resources.Validation_Title_IsNullTemplate, Resources.Job );
      }
      catch( TooLongException exc )
      {
        errorText = string.Format( Resources.Validation_String_TooLong, Resources.Validation_Title, exc.MaxLength );
      }

      if( !_checkNameUniqueness( name ) )
        errorText = Resources.Validation_Job_IsNotUnique;

      SetComment( _titleProperty, Property.Name, errorText ?? Resources.CreateJob_Name_Descripition, errorText == null );
    }

    private void SetDescription( string description )
    {
      _job.Description = description;

      string errorText = null;
      try
      {
        _validator.Validate( _job, () => _job.Description );
      }
      catch( TooLongException exc )
      {
        errorText = string.Format( Resources.Validation_String_TooLong, Resources.Validation_Description, exc.MaxLength );
      }

      SetComment( _descriptionProperty, Property.Description, errorText ?? Resources.CreateJob_Description_Description, errorText == null );
    }

    private void SetComment( EntityProperty property, Property propertyKey, string comment, bool valid )
    {
      property.Comment = comment;
      if( valid )
      {
        property.CommentType = CommentType.Normal;
        SetPropertyValid( propertyKey );
      }
      else
      {
        property.CommentType = CommentType.Error;
        SetPropertyInvalid( propertyKey );
      }
    }
    #endregion

    #region enum Property
    [Flags]
    private enum Property
    {
      Name = 1,
      Description = 2,
      All = Name | Description,
    }
    #endregion
  }
}